package com.sparrow.common.ranklist;

import java.util.*;
import java.util.function.Consumer;

/**
 * 排行榜实现
 */
public class RankList {
    /**
     * 榜单元素缓存 在榜的和不在榜的都在
     */
    private Map<Long, RankElement> rankerMap;

    private List<RankElement> rankList;

    private List<Consumer<? super RankElement>> updateListeners;

    private int capacity;

    public RankList() {

    }

    public int getCapacity() {
        return capacity;
    }

    public RankList(int capacity) {
        this.capacity = capacity;
        this.rankList = new ArrayList<>();
        this.rankerMap = new HashMap<>();
        this.updateListeners = new ArrayList<>();
    }

    public List<RankElement> getRankList() {
        return rankList;
    }

    public void clear() {
        this.rankerMap.clear();
        for (RankElement e : this.rankList) {
            e.setRank(0);
            for (Consumer<? super RankElement> l : this.updateListeners) {
                l.accept(e);
            }
        }
        this.rankList.clear();
    }

    /**
     * 重排序，常用于重新加载元素列表
     * @param collection
     */
    public void resort(Collection<? extends RankElement> collection) {
        collection.forEach(e -> addElement(e));
        Collections.sort(rankList);
        int rank = 0;
        for (RankElement rankElement : rankList) {
            rank ++;
            rankElement.setRank(rank);
        }
        while (rankList.size() > capacity) {
            removeLast();
        }
    }

    /**
     * 分数变化时更新排行榜
     * @param element
     */
    public void update(RankElement element) {
        List<RankElement> updateList = new ArrayList<>();
        boolean full = rankList.size() >= capacity;
        if (!rankerMap.containsKey(element.getRankElementId())) {
            addElement(element);
            updateList.add(element);
        }

        final int rank = element.getRank();
        for (int i = rank - 1; i >= 1; i--) {
            RankElement other = rankList.get(i - 1);
            int cmp = element.compareTo(other);
            if (cmp >= 0) {
                break;
            }
            swapRank(other, element, updateList);
        }
        int size = rankList.size();
        for (int i = rank + 1; i <= size; i ++) {
            RankElement other = rankList.get(i - 1);
            int cmp = element.compareTo(other);
            if (cmp <= 0) {
                break;
            }
            swapRank(other, element, updateList);
        }

        //添加的时候 超过榜单限制了 移除超过的元素
        while (rankList.size() > capacity) {
            RankElement e = removeLast();
            if (e != null) {
                updateList.add(e);
            }
        }
        //排名下降到最后一名时，需要考虑从不在榜单的替补里面拿一个最大的来比较
        if (element.getRank() == capacity && rank < element.getRank()) {
            Optional<RankElement> max = rankerMap.values().stream().filter(e -> e.getRank() == 0).max((a, b) -> a.compareTo(b));
            if (max.isPresent()) {
                RankElement other = max.get();
                int cmp = other.compareTo(element);
                if (cmp < 0) {
                    setRank(other, element.getRank());
                    updateList.add(other);

                    element.setRank(0);
                    updateList.add(element);
                }
            }
        }
        triggerUpdateListener(updateList);
    }

    private boolean canEnter(RankElement element) {
        return element.canEnterRankList();
    }

    private RankElement removeLast() {
        RankElement remove = rankList.remove(rankList.size() - 1);
        if (remove != null) {
            remove.setRank(0);
            return remove;
        }
        return null;
    }

    private void swapRank(RankElement other, RankElement element, List<RankElement> updateList) {
        int oldRank = other.getRank();
        setRank(other, element.getRank());
        setRank(element, oldRank);
        updateList.add(other);
        updateList.add(element);
    }

    private void setRank(RankElement other, int rank) {
        other.setRank(rank);
        rankList.set(other.getRank() - 1, other);
    }

    private void addElement(RankElement element) {
        RankElement pre = rankerMap.put(element.getRankElementId(), element);
        if (pre != null) {
            return;
        }
        rankList.add(element);
        element.setRank(rankList.size());
    }

    public void addUpdateListener(Consumer<? super RankElement> listener) {
        updateListeners.add(listener);
    }

    /**
     * 移除排行榜元素
     * @param target
     */
    public void remove(RankElement target) {
        RankElement remove = rankerMap.remove(target.getRankElementId());
        if (remove == null) {
            return;
        }
        List<RankElement> updateList = new ArrayList<>();
        updateList.add(target);
        if (target.getRank() > 0) {
            boolean full = rankList.size() == capacity;
            //后面的补上来
            for (int i = target.getRank() + 1; i <= rankList.size(); i++) {
                RankElement other = rankList.get(i - 1);
                //排名往前
                setRank(other, i - 1);
            }
            target.setRank(0);
            rankList.remove(rankList.size() - 1);
            //找替补
            if (rankList.size() < capacity) {
                Optional<RankElement> max = rankerMap.values().stream().filter(e -> e.getRank() == 0).max((a, b) -> a.compareTo(b));
                if (max.isPresent()) {
                    RankElement other = max.get();
                    update(other);
                }
            }
        }
        triggerUpdateListener(updateList);
    }

    private void triggerUpdateListener(List<RankElement> updateList) {
        for (RankElement e : updateList) {
            for (Consumer<? super RankElement> l : updateListeners) {
                l.accept(e);
            }
        }
    }
}
